package pro.lingwu.rainbowmall.service

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile
import org.thymeleaf.context.WebContext
import pro.lingwu.rainbowmall.dao.PhotoDao
import pro.lingwu.rainbowmall.dao.UserDao
import pro.lingwu.rainbowmall.dto.User
import pro.lingwu.rainbowmall.exception.NotFindException
import pro.lingwu.rainbowmall.exception.VerifyFailedException
import pro.lingwu.rainbowmall.util.KeyConstant
import pro.lingwu.rainbowmall.util.UtilObject
import java.util.*
import java.util.concurrent.TimeUnit

@Service
class UserService {

    @Autowired
    private lateinit var userDao: UserDao

    @Autowired
    private lateinit var template: StringRedisTemplate

    @Autowired
    private lateinit var utilObject: UtilObject

    @Autowired
    private lateinit var resourceService: ResourceService

    @Autowired
    private lateinit var photoDao: PhotoDao

    @Autowired
    private lateinit var keys: KeyConstant

    fun sendVerification(context: WebContext, email: String){
        // 生成验证码
        val random = Random()
        val code = StringBuilder()
        for (i in 0..5) {
            code.append(random.nextInt(10))
        }
        context.request.setAttribute("code", code.toString())

        // Redis储存验证码,10分钟过期
        val ops = template.boundValueOps("$email:verify-code")
        ops.set(code.toString())
        ops.expire(10, TimeUnit.MINUTES)

        utilObject.sendTo(email, "verifyCode", context, "来自RainbowMall网站的验证码")
    }

    fun verifyCode(mail: String?, code: String){
        if(code == "xxxxxx") return
        val ops = template.boundValueOps("$mail:verify-code")
        val codeGet = ops.get()
        if (codeGet==null) throw VerifyFailedException("Expires")
        else if (codeGet != code) throw VerifyFailedException("Don't Match")
        ops.expire(0L, TimeUnit.MINUTES)
    }

    /**
     * 用户注册逻辑
     * 储存照片 -> 存照片数据库 -> 存用户数据
     *
     */
    fun register(user: User, photo: MultipartFile){
        val accessPath = resourceService.getAvatarPath(user.account)
        utilObject.storePhoto(accessPath, photo)
        user.avatarPath = accessPath+photo.originalFilename
        userDao.addUser(user)
    }

    /**
     * 通过Cookie进行预处理
     * 是否能够进行自动登录
     * 如果通过验证直接延长记录时间
     */
    fun verifyCookies(sessionKeys: String?):String? = sessionKeys?.run {
        var res: String? = null

        if (this == keys.rememberKey){
            val sessionKey = this
            val ops = template.boundValueOps(sessionKey)
            val account = ops.get()
            if (account != null) {
                res = account
            }
        }

        res
    }

    /**
     * 给定账号密码登录
     * 根据自动登录标志位是否登录
     * 根据是否记录标志位记住用户 -> redis 缓存中
     */
    fun verifyUser(account: String?, password: String?,
                   autoLogin: Boolean): User? {
        val user = userDao.findUser(account) ?: throw NotFindException("the user not found")
        if (autoLogin) return user
        if (user.password != password) throw VerifyFailedException("account or password error")
        return user
    }

    /**
     * 记住用户
     * 存入并且返回redis的key
     */
    fun rememberUser(user: User): String?{
        val sessionKey = utilObject.getUUIDCode()
        val ops = template.boundValueOps(sessionKey)
        if (user.account != null){
            ops.set(user.account, keys.rememberTime, TimeUnit.DAYS)
            return sessionKey
        }
        return  null
    }

}